package org.example.exam;

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;

/**
 * 抽象考题
 *
 * @author bobo
 * @since 2024/4/27
 */
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, defaultImpl = AbstractExam.class, property = "classSimpleName")
@JsonSubTypes({
		@JsonSubTypes.Type(value = BaseExam.class, name = "QrExam")
})
public class AbstractExam {
	private static final Logger logger = Logger.getLogger(AbstractExam.class.getName());

	public String headings ;
	public String subheading;
	public String content;
	public String type;
	public double errorTolerant = 0.5;
	public String standardAnswer;
	public double score;

	public AbstractExam() {

	}

	public AbstractExam(String headings, String subheading, String content, String type, double errorTolerant, String standardAnswer, double score) {
		this.headings = headings;
		this.subheading = subheading;
		this.content = content;
		this.type = type;
		this.errorTolerant = errorTolerant;
		this.standardAnswer = standardAnswer;
		this.score = score;
	}

	public double correctTheExaminationPaper(String answer) {
		return jaccardSimilarity(answer, standardAnswer);
	}

	public double correctTheExaminationPaperAndPrint(String answer) {
		double score = jaccardSimilarity(answer, standardAnswer);
		String print = print();
		double getScore = score < this.errorTolerant ? 0f : score * this.score;
		logger.info(String.format(print, answer, this.score, getScore));
		return getScore;
	}


	public String printTitle() {
		return "\n - 考题详情:\n" +
				" - 考题标题: " + headings + '\n' +
				" - 考题副标题: " + subheading + '\n' +
				" - 考题内容: " + content + '\n' +
				" - 考题容错: " + errorTolerant + "(0~1之间，1表示不容错)" + '\n' +
				" - 考题总分: " + score + '\n';
	}

	public String print() {
		return "\n 考题详情:\n" +
				" - 考题标题: \n        " + headings + '\n' +
				" - 考题副标题: \n        " + subheading + '\n' +
				" - 考题内容: \n        " + content + '\n' +
				" - 标准答案: \n        " + standardAnswer + '\n' +
				" - 考题容错: \n        " + errorTolerant + "(0~1之间，1表示不容错)" + '\n' +
				" - 你的答案: \n        %s" + '\n' +
				" - 考题总分: %f" + '\n' +
				" - 你的分数: %f";
	}

	public double levenshteinDistance(String s1, String s2) {
		int[][] dp = new int[s1.length() + 1][s2.length() + 1];

		for (int i = 0; i <= s1.length(); i++) {
			dp[i][0] = i;
		}

		for (int j = 0; j <= s2.length(); j++) {
			dp[0][j] = j;
		}

		for (int i = 1; i <= s1.length(); i++) {
			for (int j = 1; j <= s2.length(); j++) {
				if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
					dp[i][j] = dp[i - 1][j - 1];
				} else {
					dp[i][j] = Math.min(dp[i - 1][j - 1], Math.min(dp[i - 1][j], dp[i][j - 1])) + 1;
				}
			}
		}

		return dp[s1.length()][s2.length()];
	}

	public double jaccardSimilarity(String s1, String s2) {

		// 使用正则表达式移除中英文特殊字符
		s1 = s1.replaceAll("[^a-zA-Z0-9\\u4e00-\\u9fa5]", "");
		s2 = s2.replaceAll("[^a-zA-Z0-9\\u4e00-\\u9fa5]", "");

		Set<String> set1 = new HashSet<>();
		Set<String> set2 = new HashSet<>();

		for (int i = 0; i < s1.length(); i++) {
			set1.add(String.valueOf(s1.charAt(i)));
		}

		for (int i = 0; i < s2.length(); i++) {
			set2.add(String.valueOf(s2.charAt(i)));
		}

		Set<String> intersection = new HashSet<>(set1);
		intersection.retainAll(set2);

		Set<String> union = new HashSet<>(set1);
		union.addAll(set2);

		return (double) intersection.size() / union.size();
	}
}
